#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_timer.h"
#include "driver/usb_serial_jtag.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_check.h"
#include "lvgl.h"
#include "esp_lvgl_port.h"

#define BUF_SIZE (512)

#define PRINTER_SPI_HOST    SPI2_HOST

#define PIN_NUM_MISO -1
#define PIN_NUM_MOSI 15
#define PIN_NUM_CLK  16
#define PIN_NUM_CS   -1

#define PIN_NUM_LAT GPIO_NUM_13 
#define PIN_NUM_VH GPIO_NUM_14

#define PIN_NUM_STB1 GPIO_NUM_6
#define PIN_NUM_STB2 GPIO_NUM_5
#define PIN_NUM_STB3 GPIO_NUM_4
#define PIN_NUM_STB4 GPIO_NUM_3
#define PIN_NUM_STB5 GPIO_NUM_2
#define PIN_NUM_STB6 GPIO_NUM_1

uint8_t pin_stbs[] = {  
                    PIN_NUM_STB1,PIN_NUM_STB2,PIN_NUM_STB3,
                    PIN_NUM_STB4,PIN_NUM_STB5,PIN_NUM_STB6
                };

lv_obj_t *state_label;                

static spi_device_handle_t spi_handle;
void init_printer_spi(){
    esp_err_t ret;
    
    spi_bus_config_t buscfg = {
        .miso_io_num = PIN_NUM_MISO,
        .mosi_io_num = PIN_NUM_MOSI,
        .sclk_io_num = PIN_NUM_CLK,
        .quadwp_io_num = -1,
        .quadhd_io_num = -1,
        .max_transfer_sz = 48
    };
    spi_device_interface_config_t devcfg = {

        .clock_speed_hz = 2 * 1000 * 1000,     //Clock out at 26 MHz
        .mode = 0,                              //SPI mode 0
        .spics_io_num = PIN_NUM_CS,             //CS pin
        .queue_size = 7,                        //We want to be able to queue 7 transactions at a time
        .pre_cb = NULL, //Specify pre-transfer callback to handle D/C line
    };
    // 初始化SPI总线
    ret = spi_bus_initialize(PRINTER_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
    ESP_ERROR_CHECK(ret);
    // 将打印机相关配置添加到SPI
    ret = spi_bus_add_device(PRINTER_SPI_HOST, &devcfg, &spi_handle);
    ESP_ERROR_CHECK(ret);
}

static void init_vh(){
    gpio_config_t vh_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_VH
    };
    ESP_ERROR_CHECK(gpio_config(&vh_gpio_config));

    gpio_set_level(PIN_NUM_VH,0);
}

static void init_lat(){
    gpio_config_t lat_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = 1ULL << PIN_NUM_LAT
    };
    ESP_ERROR_CHECK(gpio_config(&lat_gpio_config));

    gpio_set_level(PIN_NUM_LAT,1);
}

void init_stbs(){
    gpio_config_t stb_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .pin_bit_mask = (1ULL << PIN_NUM_STB1)|(1ULL << PIN_NUM_STB2)|(1ULL << PIN_NUM_STB3)|(1ULL << PIN_NUM_STB4)|(1ULL << PIN_NUM_STB5)|(1ULL << PIN_NUM_STB6)
    };
    ESP_ERROR_CHECK(gpio_config(&stb_gpio_config));

    for (size_t i = 0; i < 6; i++)
    {
        gpio_set_level(pin_stbs[i],0);
    }

}

void print_one_line(uint8_t* data){
    esp_err_t ret;
    spi_transaction_t t;
    
    memset(&t, 0, sizeof(t));       //Zero out the transaction
    uint8_t len = 48;
    t.length = len * 8;             //Len is in bytes, transaction length is in bits.
    t.tx_buffer = data;             //Data
    ret = spi_device_transmit(spi_handle, &t); //Transmit!
    assert(ret == ESP_OK);
    
    // 数据锁存
    gpio_set_level(PIN_NUM_LAT,0);
    esp_rom_delay_us(1); 
    gpio_set_level(PIN_NUM_LAT,1);
    // 加热头一次工作
    for (size_t i = 0; i < 6; i++)
    {
        gpio_set_level(pin_stbs[i],1);
        //esp_rom_delay_us(2000); 
        vTaskDelay(pdMS_TO_TICKS(2));
        gpio_set_level(pin_stbs[i],0);
        esp_rom_delay_us(20);
    }
}

// 你要传输的数据结构
typedef struct {
  uint8_t data[48];
} PrinterData;

static QueueHandle_t printer_data_queue = NULL;

extern void bsp_step_move_steps(uint16_t steps);
extern void bsp_step_stop();
void update_state_label(char * state_str);

static void receive_task(void *arg)
{
    // Configure USB SERIAL JTAG
    usb_serial_jtag_driver_config_t usb_serial_jtag_config = {
        .rx_buffer_size = BUF_SIZE,
        .tx_buffer_size = BUF_SIZE,
    };

    ESP_ERROR_CHECK(usb_serial_jtag_driver_install(&usb_serial_jtag_config));
    ESP_LOGI("usb_serial_jtag echo", "USB_SERIAL_JTAG init done");

    // Configure a temporary buffer for the incoming data
    uint8_t *data = (uint8_t *) malloc(BUF_SIZE);
    if (data == NULL) {
        ESP_LOGE("usb_serial_jtag echo", "no memory for data");
        return;
    }

    PrinterData printerData;

    while (1) {
        memset(data,0,sizeof(data));
        // 读取USB串口数据
        int len = usb_serial_jtag_read_bytes(data, 48, pdMS_TO_TICKS(50));
        
        
        // 根据长度判断接下来该怎么办
        if (len) {
            if(len == 4){
                uint8_t head = data[0];
                uint8_t cmd = data[1];
                uint8_t check = data[2];
                uint8_t tail = data[3];
                if(head == 0x7b && tail == 0x7a && check == 0x00){
                    switch(cmd){
                        case 0x01: // 打开加热头
                            printf("open hot\n");
                            // 打开总开关
                            gpio_set_level(PIN_NUM_VH,1);
                            update_state_label("open hot");
                            break;
                        case 0x02: // 关闭加热头
                            printf("close hot\n");
                            gpio_set_level(PIN_NUM_VH,0);
                            update_state_label("close hot");
                            break;
                        case 0x03: // 让纸张走几步
                            printf("move step\n");
                            bsp_step_move_steps(80);
                            bsp_step_stop();
                            update_state_label("move step ->stop");
                            break;
                    }
                }
            }else if (len == 48){
                memcpy(printerData.data, data, 48);
                BaseType_t xStatus = xQueueSend(printer_data_queue, &printerData, portMAX_DELAY);
                if (xStatus != pdPASS) {
                    printf("数据发送失败");
                }
                //print_one_line(data);
                // 移动4步
                //bsp_step_move_steps(4);
                //printf("print data\n");
                //update_state_label("print data");
            }else{
                printf("data len error:%d\r\n",len);
            }
        }
    }
}

void printData_task(){
    PrinterData received_data;
    BaseType_t xStatus;
    while(1){
        xStatus = xQueueReceive(printer_data_queue, &received_data, portMAX_DELAY);
        if (xStatus == pdPASS) {
            print_one_line(received_data.data);
            bsp_step_move_steps(4);
        }
    }
}


void example_printer_app_main(void){
    // 初始化SPI总线
    init_printer_spi();
    // 初始化锁存器
    init_lat();
    // 初始化STB加热头
    init_stbs();
    // 初始化加热头总开关
    init_vh();
    // 初始化步进电机
    extern void bsp_step_init();
    bsp_step_init();

    // 创建消息队列
    printer_data_queue = xQueueCreate(10, sizeof(PrinterData));

    // 启动串口接收线程
    xTaskCreate(receive_task, "USB SERIAL PRINTER", 4096, NULL, 5, NULL);

    xTaskCreate(printData_task, "print data task", 2048, NULL, 24, NULL);



    // 启动屏幕显示 
    extern void example_ssd1306_main(void);
    example_ssd1306_main();
    //xTaskCreate(example_ssd1306_main, "SSD1306 DEMO", 4096, NULL, 10, NULL);

    if (lvgl_port_lock(0)) {
        extern lv_disp_t *disp;
        lv_obj_t *scr = lv_disp_get_scr_act(disp);
        state_label = lv_label_create(scr);
        lv_label_set_long_mode(state_label, LV_LABEL_LONG_SCROLL_CIRCULAR); /* Circular scroll */
        lv_label_set_text(state_label, "init success");
        /* Size of the screen (if you use rotation 90 or 270, please set disp->driver->ver_res) */
        lv_obj_set_width(state_label, disp->driver->hor_res);
        lv_obj_align(state_label, LV_ALIGN_LEFT_MID, 0, 0);
        lvgl_port_unlock();
    }
}

void update_state_label(char * state_str){
    if (lvgl_port_lock(0)) {
        lv_label_set_text(state_label, state_str);
        // Release the mutex
        lvgl_port_unlock();
    }
}